﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using ConsoleVigenereMeter;
using System.Collections;

namespace VigenereMeter
{
    /// <summary>
    /// Interaction logic for Explanation.xaml
    /// </summary>
    public partial class Explanation : Window
    {
        string cipher;
        string key;
        string maxOccurence = "";
        int totalMaxOccur = 0;
        SortedDictionary<int, int> divisorContainer = new SortedDictionary<int, int>();

        public Explanation(string cipher, string key)
        {
            InitializeComponent();

            // check chiper
            if (cipher.Length < 1 || key.Length < 1)
            {
                throw new Exception("cipher is empty");
            }

            // check val
            if (cipher.Length < 1 || key.Length < 1)
            {
                throw new Exception("key is empty");
            }

            this.cipher = cipher;
            this.key = key;

            Evaluate();
        }

        private void Evaluate()
        {
            Kasiski kasiski = new Kasiski(cipher);
            Dictionary<string, ArrayList> result = kasiski.SearchRedundantString(key.Length);
            StringBuilder sb = new StringBuilder();

            if (result.Count > 0)
            {
                // Occurence
                GenerateOccurence(result, sb);

                // Available Length
                CalculateAvailableLength(result);

                // Set Log
                textBox.Text = "Max occurence : \"" + maxOccurence + "\" (Total : " + totalMaxOccur + ")\nFactor (Visible Length) in \"" + maxOccurence + "\" : " + AvailableLengthToString() + "\n" + sb.ToString();
            }

            // Set Key's Strength
            StrengthOfKeyToString();
        }

        private void GenerateOccurence(Dictionary<string, ArrayList> result, StringBuilder sb)
        {
            int count;
            int i;

            // Generate Occurence
            foreach (KeyValuePair<string, ArrayList> val in result)
            {
                count = val.Value.Count;

                // Set totalMaxOccur
                if (totalMaxOccur < count)
                {
                    totalMaxOccur = count;
                    maxOccurence = val.Key;
                }

                if (count > 1)
                {
                    sb.Append("Key \"" + val.Key + "\" : " + count + " occurence. Position : ");
                    for (i = 0; i < count - 1; ++i)
                    {
                        sb.Append(val.Value[i] + ", ");
                    }
                    sb.Append(val.Value[i] + "\n\n");
                }
            }
        }

        private void CalculateAvailableLength(Dictionary<string, ArrayList> result)
        {
            // Generate Divisor (Avalaible Length)
            ArrayList array = result[maxOccurence];
            int length = array.Count - 1;
            int j;
            for (j = 0; j < length; ++j)
            {
                AddToDivisorContainer(CalculateDivisor((int)array[j + 1] - (int)array[j]));
            }
        }

        private void StrengthOfKeyToString()
        {
            if (divisorContainer.ContainsKey(key.Length))
            {
                textBlockStrength.Text = "Key is not strength. See Log below.";
            }
            else
            {
                textBlockStrength.Text = "Key is strong. There are no occurence in cipher text.";
            }
        }

        private string AvailableLengthToString()
        {
            StringBuilder sb = new StringBuilder();

            // Most value
            foreach (KeyValuePair<int, int> val in divisorContainer)
            {
                sb.Append(val.Key + ", ");
            }

            if (sb.Length > 1)
            {
                // Remove last ", "
                sb.Remove(sb.Length - 2, 2);
                sb.Append("\n");
            }

            return sb.ToString();
        }

        private void IntersectDivisors()
        {
            foreach (KeyValuePair<int, int> val in divisorContainer)
            {
                if (val.Value < 2)
                {
                    divisorContainer.Remove(val.Key);
                }
            }
        }

        private void AddToDivisorContainer(ArrayList array)
        {
            int length = array.Count;
            int key;

            for (int i = 0; i < length; ++i)
            {
                key = (int)array[i];
                if (divisorContainer.ContainsKey(key))
                {
                    divisorContainer[key] = divisorContainer[key] + 1;
                }
                else
                {
                    divisorContainer[key] = 1;
                }
            }
        }

        private ArrayList CalculateDivisor(int number)
        {
            ArrayList divisor = new ArrayList();
            int div = (number / 2) + 1;
            for (int i = 1; i < div; ++i)
            {
                if (number % i == 0)
                {
                    divisor.Add(i);
                }
            }

            return divisor;
        }
    }
}
